import {
  LinkedListDoubly,
} from '../LinkedList/index';

export class ArrayStack {
  protected items: any[];

  public constructor(...initials: any[]) {
    this.items = [...initials];
  }

  public push(element: any) {
    this.items.push(element);
  }

  public pop() {
    return this.items.pop();
  }

  public peak() {
    return this.items[this.items.length - 1];
  }

  public isEmpty() {
    return this.items.length === 0;
  }

  public clear() {
    this.items = [];
  }

  public size() {
    return this.items.length;
  }
}

export class ObjectStack {
  protected stack: Map<number, any>;
  protected count: number;

  public constructor(...initials: any[]) {
    this.count = 0;
    this.stack = new Map();

    initials.forEach((item, index) => {
      this.stack.set(index, item);
      this.count = index + 1;
    });
  }

  public push(element: any) {
    this.stack.set(this.count, element);
    this.count++;
  }

  public pop() {
    if (this.isEmpty()) {
      return undefined;
    }

    this.count--;
    
    const result = this.stack.get(this.count);
    this.stack.delete(this.count);

    return result;
  }

  public peak() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.stack.get(this.count - 1);
  }

  public isEmpty() {
    return this.count === 0;
  }

  public clear() {
    this.stack = new Map();
    this.count = 0;
  }

  public size() {
    return this.count;
  }

  public toString() {
    if (this.isEmpty()) {
      return '';
    }

    let str = `${this.stack.get(0)}`;

    for (let i = 1; i < this.count; i++) {
      str = `${str},${this.stack.get(i)}`;
    }

    return str;
  }
}

export class LinkedListStack {
  protected stack: LinkedListDoubly;

  public constructor(...initials: any[]) {
    this.stack = new LinkedListDoubly([...initials]);
  }

  public push(element: any) {
    const size = this.size();
    this.stack.insert(element, size);
  }

  public pop() {
    if (this.isEmpty()) {
      return undefined;
    }
    const resultIndex = this.stack.size() - 1;
    const result = this.stack.getElementAt(resultIndex);
    this.stack.removeAt(resultIndex);

    return result;
  }

  public peak() {
    if (this.isEmpty()) {
      return undefined;
    }
    const size = this.size();
    return this.stack.getElementAt(size - 1);
  }

  public isEmpty() {
    return this.stack.size() === 0;
  }

  public clear() {
    this.stack.clear();
  }

  public size() {
    return this.stack.size();
  }

  public toString() {
    return this.stack.toString();
  }
}
